package lottery.impl;

import java.util.List;

import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import lottery.RemoteLotteryGameService.LocalLotteryGameService;
import lottery.RemoteLotteryGameService;
import lottery.impl.entities.Bet;
import lottery.impl.entities.Lottery;
import lottery.msgs.LotteryBet;
import lottery.msgs.LotteryResult;


@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public class LotteryGameServiceImpl implements RemoteLotteryGameService, LocalLotteryGameService{
	@PersistenceContext(unitName="lottery")
	EntityManager em;

	@Override
	public void placeBet(LotteryBet lotteryBet) throws Exception {
		
		// Retrieve the on going lottery
		Query query = em.createNamedQuery("lottery.onGoing");
		
		Lottery onGoinglottery = null; 
		try{
			onGoinglottery = (Lottery) query.getSingleResult();		
		}catch(NoResultException e){
			throw new Exception("No on going lotteries.");
		}
		
		// Define new bet based on parameters
		Bet newBet = new Bet();
		
		newBet.setLottery(onGoinglottery);
		newBet.setAmountBetted(lotteryBet.getAmountBetted());
		newBet.setResultBetted(lotteryBet.getResultBetted());
		newBet.setAmountDue(0.0);
		newBet.setNotified(false);
		newBet.setToken(lotteryBet.getTokenId());
		newBet.setSourceSystemId(lotteryBet.getSourceSystemId());
		
		// Persist the new bet
		try{
			em.persist(newBet);
		}
		catch(Exception e){
			throw new Exception("Error creating new bet.", e);
		}
		
		// Update the lottery total amount
		onGoinglottery.setTotalAmount(onGoinglottery.getTotalAmount() + lotteryBet.getAmountBetted());
		
		// Update the lottery in the database
		try{
			em.persist(onGoinglottery);
		}
		catch(Exception e){
			throw new Exception("Error updating lottery total amount.", e);
		}		
	}

	@Override
	public LotteryResult[] retrieveResults(int sourceSystemId) throws Exception {
		
		// Retrieve the bets that have not been notified yet for the specified system
		Query query = em.createNamedQuery("bet.unnotifiedBySystem");
		query.setParameter("sourcesystemid", sourceSystemId);
		
		@SuppressWarnings("unchecked")
		List<Bet> retrievedBets = query.getResultList();

		// Check if the user has friends
		if(retrievedBets.isEmpty()){
			return new LotteryResult[0];
		}
		
		// Create the array to return the results
		LotteryResult[] retrievedResuts = new LotteryResult[retrievedBets.size()];

		// Define the index
		int index = 0;
		
		// Iterate through the unnotified results, build the result and update it
		for( Bet retrievedBet : retrievedBets ){
			
			LotteryResult newResult = new LotteryResult(retrievedBet.getToken(), retrievedBet.getLottery().getLotteryDescription(),	retrievedBet.getLottery().getWinMultiplier(), retrievedBet.getLottery().getResult(), retrievedBet.getResultBetted(), false,retrievedBet.getAmountDue());
			
			// Check if the result contains a winner
			if(retrievedBet.getAmountDue() > 0){
				newResult.setWinner(true);
			}
			
			// Update the database so the result is now marked as notified
			retrievedBet.setNotified(true);
			
			// Persist the updated bet
			try{
				em.persist(retrievedBet);
			}
			catch(Exception e){
				throw new Exception("Error updating bet.", e);
			}
			
			// Load the extracted result and update the index
			retrievedResuts[index] = newResult;
			index++;
		}
		
		return retrievedResuts;
	}
}
